/**
 * Created by eahom on 2016/10/12.
 *
 * This file used to remove native cordova code for iOS PAPersonalDoctor App.
 * H5 teams not recommand reference this file directly, otherwise reference 
 * the pajk_hybrid_index.js, while automatically referencing the new hybrid js
 * or old cordova js.
 * 
 * The data structure from Native to H5 is:
 * {
 *    callbackId: string,(h5 generate)
 *    ret: number,(0:success, other:failure)
 *    data: json string,
 * }
 *
 * The data structure from H5 to Native(old cordova):
 * {
 *    options: {
 *      action: number,
 *      type: number,
 *      data: object,
 *      source: number,
 *      callbackId: string
 *    }
 * }
 * 
 */
 
(function(){
    window.hybrid = {
        DEBUG: false,
        inc: 1,
        loggerInfo: [],
        hybridEvents: {},
        bridge: {},
        registedEvents: {},
        logger: function(log) {
            if (window.hybrid.DEBUG) {
                window.hybrid.loggerInfo.push(log);
            }
        },
        loadUrl: function(url) {
            var iFrame = null;
            iFrame = document.createElement('iframe');
            iFrame.setAttribute('src', url);
            iFrame.setAttribute('style', 'display:none');
            iFrame.setAttribute('height', '0px');
            iFrame.setAttribute('width', '0px');
            iFrame.setAttribute('frameborder', '0');
            document.body.appendChild(iFrame);
            iFrame.parentNode.removeChild(iFrame);
            iFrame = null;
            window.hybrid.logger('[h5 event]request ' + url);
        },
        mockDeviceReady: function() {
            var evtDeviceReady = document.createEvent('Events');
            evtDeviceReady.initEvent('deviceready', false, false);
            document.dispatchEvent(evtDeviceReady);
            window.hybrid.logger('[mock deviceready]mock cordova deviceready event, dispatched.');
            window.hybrid.hybridEvents.deviceready = evtDeviceReady;
            window.hybrid.logger('[mock deviceready]mock cordova deviceready event, add to hybridEvents.');
        },
        generateCallbackId: function() {
            return Math.floor(Math.random() * 2e9) + window.hybrid.inc++ + '';
        },
        nativeCallback: function(callbackId, status, data) {
            window.hybrid.logger('[native callback]callbackId: ' + callbackId + ', status: ' + status + ', data:' + JSON.stringify(data));
            if (status == 0) {
                window.hybrid.bridge[callbackId].succ && window.hybrid.bridge[callbackId].succ(data);
            } else {
                window.hybrid.bridge[callbackId].fail && window.hybrid.bridge[callbackId].fail(data);
            }

            window.hybrid.logger('[native callback]remove callbackId ' + callbackId + ' from h5 request callback list.');
            delete window.hybrid.bridge[callbackId];
        },
        isEmptyObject: function(obj) {
            var o;
            for (o in obj)
                return false;
            return true;
        },
        nativeEventTrigger: function(event, params) {
            window.hybrid.logger('[native event dispatched]event:' + event + ' params:' + JSON.stringify(params));
            var eventCallbackHandlers = window.hybrid.registedEvents[event] || [];
            eventCallbackHandlers.forEach(function(handler, idx){
                if (handler) {
                    window.hybrid.logger('[native event dispatched]event:' + event + ' idx:' + idx + ', excute handler.');
                    handler(params);
                } else {
                    window.hybrid.logger('[native event dispatched]event:' + event + ' idx:' + idx + ', skip.');
                }
            });
        }
    };
    var hybrid = window.hybrid;
    var logger = window.hybrid.logger;

    if (window.hybrid.DEBUG) {
        window.onerror = function(msg, url, line) {
            logger('[window onerror]Error in ' + url + ' (line #"' + line + '"): ' + msg);
            return false;
        };
        logger('[...]add window error listener.');
    }
    logger('[...]define window pajkPostMessage begin.');
    Object.defineProperties(window, {
        'pajkPostMessage': {
            value: function(success, error, options) {
                if (success != null || error != null) {
                    var callbackId = hybrid.generateCallbackId();
                    options.callbackId = callbackId;
                    hybrid.bridge[callbackId] = {succ: success, fail: error};
                    logger('[h5 cordova event]add callbackId: ' + callbackId + ' to h5 request callback list.');
                }
                var cordovaReq = 'pajk://__hybrid__/' + encodeURIComponent(JSON.stringify(options));
                logger({options: JSON.stringify(options), scheme: cordovaReq, timestamp:Date.now()});
                hybrid.loadUrl(cordovaReq);
            },
            writable: false,
        },
        'pajkDispatchScheme': {
            value: function(success, failure, content, scheme) {
                var scheme_protocol = 'pajk';
                if (navigator.userAgent.toLowerCase().match(/\s\w+appversion\/\d+/)) {
                    var appinfo = navigator.userAgent.toLowerCase().match(/\w+appversion\/\d+/)[0];
                    scheme_protocol = appinfo.substring(0, appinfo.indexOf('appversion'));
                }

                var schemeReq = scheme_protocol + '://' + scheme;

                if (!content || !(typeof content === 'object')) {
                    content = content || {};
                }
                if (!hybrid.isEmptyObject(content)) {
                    schemeReq += '?content=' + encodeURIComponent(JSON.stringify(content));                
                }

                if (success != null || failure != null) {
                    var schemeCallbackId = hybrid.generateCallbackId();
                    hybrid.bridge[schemeCallbackId] = {succ: success, fail: failure};
                    if (null != schemeCallbackId) {
                        if (schemeReq.indexOf('?') != -1) {
                            schemeReq += '&callbackId=' + schemeCallbackId;
                        } else {
                            schemeReq += '?callbackId=' + schemeCallbackId;
                        }
                    }
                    logger('[H5 scheme event]add callbackId: ' + schemeCallbackId + ' to h5 request callback list.');
                }

                hybrid.loadUrl(schemeReq);
            },
            writable: false,
        },
        'pajkRegisterEvent': {
            value: function(name, handler) {
                if (typeof(name) === 'string' && name.length > 0 && typeof(handler) === 'function') {                    
                    var eventCallbackhandlers = hybrid.registedEvents[name];
                    if (!eventCallbackhandlers) {
                        eventCallbackhandlers = [];
                        hybrid.registedEvents[name] = eventCallbackhandlers;
                    }
                    
                    if (-1 === eventCallbackhandlers.indexOf(handler)) {
                        logger('[H5 regist event]event:' + name + ' handler:' + handler + ', add.');
                        eventCallbackhandlers.push(handler);
                    } else {
                        logger('[H5 regist event]event:' + name + ' handler:' + handler + ', repeat.');
                    }                    
                    var eventCallbackId = eventCallbackhandlers.indexOf(handler);
                    
                    return eventCallbackId;
                } else {
                    logger('[H5 regist event]event:' + name + ' handler:' + handler + ', param invalid.');
                }
            },
            writable: false,
        },
        'pajkUnRegisterEvent': {
            value: function(name, callbackId) {
                var eventCallbackhandlers = hybrid.registedEvents[name] || [];
                if (eventCallbackhandlers[callbackId]) {
                    eventCallbackhandlers[callbackId] = null;
                    logger('[H5 unregist event]event:' + name + ' callbackId:' + callbackId + ', unregiested.');
                } else {
                    logger('[H5 unregist event]event:' + name + ' callbackId:' + callbackId + ', not-find.');
                }
            },
            writable: false,
        }
    });
    //解决线上报错
	if(!window.jsOnMessage){
		window.jsOnMessage = function (data) {
			logger(data)
		}
	}
	if(!window.pajkOnMessage){
		window.pajkOnMessage = function (data) {
			logger(data)
		}
    }
    logger('[...]define window pajkPostMessage end.');
    hybrid.addEventListener = document.addEventListener;
    logger('[...]custom document addEventListener begin.');
    document.addEventListener = function(evt, handler, capture) {
        logger('[Custom addEventListener]event: ' + evt + ', timestamp: ' + JSON.stringify(Date.now()));
        var e = evt.toLowerCase();

        if (typeof hybrid.hybridEvents[e] != 'undefined') {
            var evtCurrent = hybrid.hybridEvents[e];
            if (evtCurrent.type == 'deviceready') {
                logger('[Custom addEventListener]deviceready fired, call handler immediately.');
                handler.call();
            } else {
                logger('[Custom addEventListener]deviceready not fired, call origin addEventListener.');
                hybrid.addEventListener.call(document, evt, handler, capture);
            }
        } else {
            logger('[Custom addEventListener]hybrid events no this event, call origin addEventListener.');
            hybrid.addEventListener.call(document, evt, handler, capture);
        }
    };
    logger('[...]custom document addEventListener end.');
    logger('[...]mock device ready begin.');
    hybrid.mockDeviceReady();
    logger('[...]mock device ready end.');
})();
